package com.xbongbong.callback.service.imp;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.api.domain.entity.ApiCallbackSetEntity;
import com.xbongbong.callback.constant.TplusConfig;
import com.xbongbong.callback.service.ApiCallBackService;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.EnableEnum;
import com.xbongbong.paas.pojo.dto.ApiCallBackRetrySwitchDTO;
import com.xbongbong.paas.pojo.dto.ApiCallBackSetDTO;
import com.xbongbong.paas.pojo.vo.ApiCallBackGetVO;
import com.xbongbong.paas.pojo.vo.ApiCallBackSetVO;
import com.xbongbong.paas.pojo.vo.RetrySwitchVO;
import com.xbongbong.paas.pojo.vo.TokenUpdateVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.redis.RedisTimeConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.DigestUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseDTO;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.pro.api.pojo.ApiCallbackSetPojo;
import com.xbongbong.pro.enums.ApiCallBackEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.OpenAppEntity;
import com.xbongbong.saas.model.ApiCallbackSetModel;
import com.xbongbong.saas.model.OpenAppModel;
import com.xbongbong.sys.domain.entity.ApiTokenEntity;
import com.xbongbong.sys.model.ApiTokenModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 *
 * @author 魏荣杰
 * @date 2019/10/10 21:53
 * @since v4.3.2.3
 * @version v4.3.2.3
 */
@Service("apiCallbackSetService")
public class ApiCallBackServiceImpl implements ApiCallBackService {
    private static final Logger LOG = LoggerFactory.getLogger(ApiCallBackServiceImpl.class);

    @Resource
    private ApiCallbackSetModel apiCallbackSetModel;
    @Resource
    private ApiTokenModel apiTokenModel;
    @Resource
    private OpenAppModel openAppModel;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private TplusConfig tplusConfig;

    /**
     * 获取公司的外部接口回调url（相应模块type没开启，返回空字符串）
     * @param corpid 公司id
     * @param type 业务类型
     * @return 回调url
     */
    @Override
    public ApiCallbackSetPojo getCorpApiCallbackUrlByType(String corpid, String type) {
        String prefix = RedisPrefixConstant.CALLBACK_URL;
        String key = corpid + "_" + type;
        ApiCallbackSetPojo apiCallbackSetPojo = JSONObject.parseObject(paasRedisHelper.getValue(prefix,key), ApiCallbackSetPojo.class);
        if (Objects.nonNull(apiCallbackSetPojo)) {
            return apiCallbackSetPojo;
        }

        apiCallbackSetPojo = new ApiCallbackSetPojo();
        ApiCallbackSetEntity apiCallbackSetEntity = getApiCallbackSet(corpid);
        List<String> urls = new ArrayList<>();
        if (Objects.nonNull(apiCallbackSetEntity)) {
            JSONObject modules = apiCallbackSetEntity.getModules();
            String callbackUrl = apiCallbackSetEntity.getCallbackUrl();
            if( "1".equals(modules.getString(type)) && StringUtil.isNotEmpty(callbackUrl)) {
                urls.add(callbackUrl);
            }
            apiCallbackSetPojo.setToken(apiCallbackSetEntity.getKey());
            apiCallbackSetPojo.setIsRetry(apiCallbackSetEntity.getIsRetry());
        }
        //获取corpid授权的第三方应用的openAppId，获取其中的回调地址
        List<String> urlList = getOpenApiCallbackUrl(corpid);
        urls.addAll(urlList);
        apiCallbackSetPojo.setUrls(urls);
        paasRedisHelper.setValue(prefix,key, apiCallbackSetPojo, RedisTimeConstant.TINY_DURATION);
        return apiCallbackSetPojo;
    }

    /**
     * 第三方回调地址获取，现在只有一个每刻报销的回调
     * @param corpid
     * @return
     */
    private List<String> getOpenApiCallbackUrl(String corpid) {
        List<String> urlList = new ArrayList<>();
        List<ApiTokenEntity> list = apiTokenModel.getByCorpidAndExistOpenApp(corpid);
        if (list.isEmpty()) {
            return urlList;
        }
        Set<Integer> openAppSet = new HashSet<>();
        for (ApiTokenEntity apiToken : list) {
            openAppSet.add(apiToken.getOpenAppId());
        }
        if (openAppSet.isEmpty()) {
            return urlList;
        }
        Map<String, Object> param = new HashMap<>();
        param.put("openAppIdIn", openAppSet);
        param.put("del", DelEnum.NORMAL.getDel());
        List<OpenAppEntity> openApps = openAppModel.findEntitys(param);
        if (!openApps.isEmpty()) {
            for (OpenAppEntity openApp : openApps) {
                String apiCallbackUrl = openApp.getApiCallbackUrl();
                if (!StringUtil.isEmpty(apiCallbackUrl)) {
                    urlList.add(apiCallbackUrl);
                }
            }
        }
        return urlList;
    }

    @Override
    public ApiCallbackSetEntity getApiCallbackSet(String corpid){
        Map<String,Object> param = new HashMap<>(16);
        param.put("corpid",corpid);
        param.put("del",0);
        param.put("start",0);
        param.put("pageNum",1);
        List<ApiCallbackSetEntity> list = apiCallbackSetModel.findEntitys(param);
        if (list.isEmpty()) {
            return null;
        }
        return list.get(0);
    }

    /**
     * 保存回调接口，保存逻辑：第一次插入，以后更新
     * @param apiCallbackSetDTO
     * @return apiCallbackSetVO
     * @throws XbbException
     */
    @Override
    public ApiCallBackSetVO save(ApiCallBackSetDTO apiCallbackSetDTO) throws XbbException {
        UserVO userVO = apiCallbackSetDTO.getLoginUser();
        if (!userVO.isAdminOrBoss()) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100017);
        }
        String corpid = apiCallbackSetDTO.getCorpid();
        String token = apiCallbackSetDTO.getToken();
        Integer isRetry = apiCallbackSetDTO.getIsRetry();
        String callBackUrl = apiCallbackSetDTO.getCallBackUrl();
        JSONObject modules = apiCallbackSetDTO.getModules();
        ApiCallbackSetEntity apiCallbackSetEntity = apiCallbackSetModel.getByCorpId(corpid);
        if (Objects.isNull(apiCallbackSetEntity)) {
            apiCallbackSetEntity = new ApiCallbackSetEntity();
            apiCallbackSetEntity.setCorpid(corpid);
        }

        JSONObject callBackModules = new JSONObject();
        if (Objects.nonNull(modules)) {
            Set<String> keySet = modules.keySet();
            for (String module : keySet) {
                ApiCallBackEnum apiCallBackModuleEnum = ApiCallBackEnum.getByAlias(module);
                if (Objects.nonNull(apiCallBackModuleEnum)) {
                    callBackModules.put(apiCallBackModuleEnum.getAlias(), modules.get(module));
                }
            }
        }
        if (StringUtil.isEmpty(callBackUrl)) {
            callBackUrl = "";
        }
        apiCallbackSetEntity.setIsRetry(isRetry);
        apiCallbackSetEntity.setKey(token);
        apiCallbackSetEntity.setModules(callBackModules);
        apiCallbackSetEntity.setCallbackUrl(callBackUrl);
        Integer id = apiCallbackSetModel.save(apiCallbackSetEntity);
        String prefix = RedisPrefixConstant.CALLBACK_URL;
        Set<String> moduleSet = callBackModules.keySet();
        for (String type : moduleSet) {
            String key = corpid + "_" + type;
            paasRedisHelper.removeValue(prefix,key);
        }
        ApiCallBackSetVO apiCallbackSetVO = new ApiCallBackSetVO();
        apiCallbackSetVO.setId(apiCallbackSetEntity.getId());
        return apiCallbackSetVO;
    }

    /**
     * api回调回显
     * @param baseDTO
     * @return apiCallBackGetVO
     * @throws XbbException
     */
    @Override
    public ApiCallBackGetVO get(BaseDTO baseDTO) throws XbbException {
        UserVO userVO = baseDTO.getLoginUser();
        if (!userVO.isAdminOrBoss()) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100017);
        }

        ApiCallBackGetVO apiCallBackGetVO = new ApiCallBackGetVO();
        String corpid = baseDTO.getCorpid();
        ApiCallbackSetEntity apiCallbackSetEntity = apiCallbackSetModel.getByCorpId(corpid);

        apiCallBackGetVO.setCorpid(corpid);
        apiCallBackGetVO.setUserId(baseDTO.getUserId());
        JSONObject modules = null;
        if (Objects.nonNull(apiCallbackSetEntity)) {
            apiCallBackGetVO.setCallBackUrl(apiCallbackSetEntity.getCallbackUrl());
            apiCallBackGetVO.setToken(apiCallbackSetEntity.getKey());
            apiCallBackGetVO.setIsRetry(apiCallbackSetEntity.getIsRetry());
            modules = apiCallbackSetEntity.getModules();
        }
        List<ApiCallBackEnum> allEnum = ApiCallBackEnum.getAllEnum();
        JSONArray jsonArray = new JSONArray();
        for (ApiCallBackEnum apiCallBackEnum : allEnum) {
            if (apiCallBackEnum.getEnable().equals(EnableEnum.CLOSE.getCode())) {
                continue;
            }
            JSONObject jsonObject = new JSONObject(4);
            jsonObject.put(StringConstant.SAAS_LINK_BUSINESS_NAME, apiCallBackEnum.getName());
            jsonObject.put(StringConstant.ATTR, apiCallBackEnum.getAlias());
            jsonObject.put(ParameterConstant.ENABLE, EnableEnum.CLOSE.getCode());
            if (Objects.nonNull(modules)) {
                Integer enable = modules.getInteger(apiCallBackEnum.getAlias());
                if (Objects.nonNull(enable) && enable.equals(EnableEnum.OPEN.getCode())) {
                    jsonObject.put(ParameterConstant.ENABLE, enable);
                }
            } else {
                jsonObject.put(ParameterConstant.ENABLE, EnableEnum.CLOSE.getCode());
            }
            jsonArray.add(jsonObject);
        }
        apiCallBackGetVO.setModules(jsonArray);

        return apiCallBackGetVO;
    }

    @Override
    public TokenUpdateVO tokenUpdate(BaseDTO baseDTO) throws XbbException {
        UserVO userVO = baseDTO.getLoginUser();
        if (!userVO.isAdminOrBoss()) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100017);
        }
        String corpid = baseDTO.getCorpid();
        //规则是公司ID + pro + 时间戳 字符串进行SHA256 然后取前32位
        String plainText = corpid + "pro" + DateUtil.getInt();
        String newToken = DigestUtil.Encrypt(plainText, "SHA-256").substring(0, 32);

        ApiCallbackSetEntity apiCallbackSetEntity = apiCallbackSetModel.getByCorpId(corpid);
        ApiCallBackSetDTO apiCallbackSetDTO = new ApiCallBackSetDTO();
        BeanUtil.copyProperties(baseDTO, apiCallbackSetDTO);
        apiCallbackSetDTO.setToken(newToken);
        apiCallbackSetDTO.setIsRetry(BasicConstant.IS_USE);
        if (Objects.nonNull(apiCallbackSetEntity)) {
            apiCallbackSetDTO.setCallBackUrl(apiCallbackSetEntity.getCallbackUrl());
            apiCallbackSetDTO.setModules(apiCallbackSetEntity.getModules());
            apiCallbackSetDTO.setIsRetry(apiCallbackSetEntity.getIsRetry());
        }
        save(apiCallbackSetDTO);
        TokenUpdateVO tokenUpdateVO = new TokenUpdateVO();
        tokenUpdateVO.setToken(newToken);
        return tokenUpdateVO;
    }

    @Override
    public RetrySwitchVO retrySwitch(ApiCallBackRetrySwitchDTO apiCallBackRetrySwitchDTO) throws XbbException {
        UserVO userVO = apiCallBackRetrySwitchDTO.getLoginUser();
        if (!userVO.isAdminOrBoss()) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100017);
        }
        String corpid = apiCallBackRetrySwitchDTO.getCorpid();
        ApiCallbackSetEntity apiCallbackSetEntity = apiCallbackSetModel.getByCorpId(corpid);
        ApiCallBackSetDTO apiCallbackSetDTO = new ApiCallBackSetDTO();
        BeanUtil.copyProperties(apiCallBackRetrySwitchDTO, apiCallbackSetDTO);
        if (Objects.nonNull(apiCallbackSetEntity)) {
            apiCallbackSetDTO.setCallBackUrl(apiCallbackSetEntity.getCallbackUrl());
            apiCallbackSetDTO.setModules(apiCallbackSetEntity.getModules());
            apiCallbackSetDTO.setToken(apiCallbackSetEntity.getKey());
        }
        save(apiCallbackSetDTO);
        RetrySwitchVO retrySwitchVO = new RetrySwitchVO();
        retrySwitchVO.setIsRetry(apiCallBackRetrySwitchDTO.getIsRetry());
        return retrySwitchVO;
    }


    @Override
    public void tplusApiCallbackSet(String corpid, Integer enable) {
        ApiCallbackSetEntity apiCallbackSet = apiCallbackSetModel.getByCorpId(corpid);
        if (Objects.isNull(apiCallbackSet)) {
            apiCallbackSet = new ApiCallbackSetEntity();
        }
        apiCallbackSet.setCorpid(corpid);
        apiCallbackSet.setCallbackUrl(tplusConfig.getBACK_URL_FOR_TPLUS());
        apiCallbackSet.setIsRetry(0);
        apiCallbackSet.setModules(ApiCallBackEnum.getTplusCallbackModule());
        if (Objects.equals(enable, BasicConstant.NO_USE)) {
            apiCallbackSet.setDel(1);
        }else {
            apiCallbackSet.setDel(0);
        }
        try {
            apiCallbackSetModel.save(apiCallbackSet);
        } catch (Exception e) {
            LOG.error("回调设置保存失败");
        }
    }
}
